package com.neusoft.gateway.filters;

import com.neusoft.gateway.redisservice.RedisService;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.neusoft.gateway.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    private static final List<String> WHITE_LIST = Arrays.asList(
            "/mcp/.*",
            "/sse/.*",
            "/UserController/login",
            "/UserController/logout",
            "/ChatClientController/.*",
            "/MessageController/.*",
            "/ClientController/getClientById",
            "/ClientCareItemController/getClientCareItemsByClientId",
            "/v3/.*",
            "/swagger-ui/.*",
            "/swagger-resources/.*",
            "/webjars/.*",
            "/error",
            "/doc.*",
            "/favicon.ico"
    );

    @Autowired
    private RedisService redisService;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().value();

        // 检查是否为OPTIONS请求（跨域预检）
        if (request.getMethod() == HttpMethod.OPTIONS) {
            return chain.filter(exchange);
        }

        // 检查是否在白名单中
        if (isPathWhiteListed(path)) {
            return chain.filter(exchange);
        }

        // 获取Authorization头
        String authHeader = getAuthHeader(request);
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            return unauthorized(exchange, "Missing or invalid Authorization header");
        }

        String token = authHeader.substring(7);

        // 检查令牌黑名单（同步调用，适用于您的服务）
        if (redisService.isTokenBlacklisted(token)) {
            return unauthorized(exchange, "Token is blacklisted");
        }

        // 验证JWT令牌
        try {
            Map<String, Claim> claims = JwtUtil.verifyToken(token);
            // 将用户信息添加到请求头，供下游服务使用
            ServerHttpRequest modifiedRequest = addUserInfoToHeaders(request, claims);
            return chain.filter(exchange.mutate().request(modifiedRequest).build());
        } catch (JWTVerificationException e) {
            return unauthorized(exchange, "Invalid or expired token");
        }
    }

    private boolean isPathWhiteListed(String path) {
        return WHITE_LIST.stream().anyMatch(pattern -> path.matches(pattern));
    }

    private String getAuthHeader(ServerHttpRequest request) {
        List<String> headers = request.getHeaders().get("Authorization");
        return (headers != null && !headers.isEmpty()) ? headers.get(0) : null;
    }

    private Mono<Void> unauthorized(ServerWebExchange exchange, String message) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json");

        // 返回标准错误响应
        String errorBody = String.format("{\"code\": 401, \"message\": \"%s\"}", message);
        return response.writeWith(Mono.just(
                response.bufferFactory().wrap(errorBody.getBytes())
        ));
    }

    private ServerHttpRequest addUserInfoToHeaders(ServerHttpRequest request, Map<String, Claim> claims) {
        // 获取用户ID和角色
        String userId = claims.get("userId") != null ? claims.get("userId").asString() : "";
        String userRole = claims.get("role") != null ? claims.get("role").asString() : "";

        // 添加到请求头
        return request.mutate()
                .header("X-User-Id", userId)
                .header("X-User-Role", userRole)
                .build();
    }

    @Override
    public int getOrder() {
        // 设置优先级为最高
        return Ordered.HIGHEST_PRECEDENCE;
    }
}